/*
   Copyright 2012 Shane Phillips

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package org.jdraw;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.security.InvalidParameterException;

public class Canvas {

	private Graphics2D g2;
	private BufferedImage image;
	private final int DEFAULT_WIDTH = 640;
	private final int DEFAULT_HEIGHT = 480;
	private int width;
	private int height;
	private Color color;

	public final int MAX_WIDTH = 2560;
	public final int MAX_HEIGHT = 1440;

	public Canvas() {
		color = Color.BLACK;
		reset();
	}

	protected BufferedImage getImage() {
		return image;
	}

	/**
	 * Enables / disables AntiAliasing
	 * 
	 * @param enabled
	 */
	public void setAntiAliasingEnabled(boolean enabled) {
		if (enabled) {
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
					RenderingHints.VALUE_ANTIALIAS_ON);
		} else {
			g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
					RenderingHints.VALUE_ANTIALIAS_OFF);
		}

	}

	/**
	 * Resets the canvas, clearing any previously drawn shapes. Resets canvas
	 * colors to default (bgColor == Color.WHITE, Color == Color.BLACK)
	 */
	public void reset() {

		if (width == 0) {
			width = DEFAULT_WIDTH;
		}
		if (height == 0) {
			height = DEFAULT_HEIGHT;
		}
		image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
		g2 = (Graphics2D) image.getGraphics();
		g2.setColor(color);
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
	}

	/**
	 * Gets the current background color of the Canvas
	 * 
	 * @return Background color of the canvas
	 */
	public Color getBackground() {
		return g2.getBackground();
	}

	/**
	 * Sets the background color of the canvas
	 * 
	 * @param r
	 *            Red value (0.0 - 1.0)
	 * @param g
	 *            Green value (0.0 - 1.0)
	 * @param b
	 *            Blue value (0.0 - 1.0)
	 */

	public void setBackground(float r, float g, float b) {
		Color c = new Color(r, g, b);
		g2.setBackground(c);
		g2.clearRect(0, 0, image.getWidth(), image.getHeight());
	}

	/**
	 * Sets the background color of the canvas
	 * 
	 * @param c
	 * 
	 * @see java.awt.Color
	 */
	public void setBackground(Color c) {
		g2.setBackground(c);
		g2.clearRect(0, 0, image.getWidth(), image.getHeight());
	}

	/**
	 * Draws a single point on the canvas at (x, y)
	 * 
	 * @param x
	 *            X Coordinate of point
	 * @param y
	 *            Y Coordinate of point
	 */
	public void drawPoint(int x, int y) {
		g2.drawLine(x, y, x, y);
	}

	/**
	 * Draws a line from (x1, y1) to (x2, y2)
	 * 
	 * @param x1
	 *            The starting X coordinate
	 * @param y1
	 *            The starting Y coordinate
	 * @param x2
	 *            The ending X coordinate
	 * @param y2
	 *            The ending Y coordinate
	 * 
	 * @see java.awt.Graphics2D#drawLine
	 */
	public void drawLine(int x1, int y1, int x2, int y2) {
		g2.drawLine(x1, y1, x2, y2);
	}

	/**
	 * Draws a square at (x,y)
	 * 
	 * @param x
	 * @param y
	 * @param sideLength
	 */
	public void drawSquare(int x, int y, int sideLength) {
		g2.drawRect(x, y, sideLength, sideLength);
	}

	/**
	 * Draws a rectangle at (x,y)
	 * 
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * 
	 * @see java.awt.Graphics2D#drawRect(int, int, int, int)
	 */
	public void drawRectangle(int x, int y, int width, int height) {
		g2.drawRect(x, y, width, height);
	}

	/**
	 * Fills the specified rectangle
	 * 
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * 
	 * @see java.awt.Graphics#fillRect(int, int, int, int)
	 */
	public void fillRectangle(int x, int y, int width, int height) {
		g2.fillRect(x, y, width, height);
	}

	/**
	 * Draws a circular or elliptical arc
	 * 
	 * @param x
	 *            The x coordinate of the upper-left corner of the arc
	 * @param y
	 *            The y coordinate of the upper-left corner of the arc
	 * @param width
	 * @param height
	 * @param startAngle
	 *            The starting angle
	 * @param arcAngle
	 *            The ending angle, relative to the starting angle
	 * 
	 * @see java.awt.Graphics2D#drawArc(int, int, int, int, int, int)
	 */
	public void drawArc(int x, int y, int width, int height, int startAngle,
			int arcAngle) {
		g2.drawArc(x, y, width, height, startAngle, arcAngle);
	}

	/**
	 * Draws a circle
	 * 
	 * @param x
	 * @param y
	 * @param radius
	 */
	public void drawCircle(int x, int y, int radius) {
		g2.drawOval(x, y, (radius * 2), (radius * 2));
	}

	/**
	 * Draws an oval
	 * 
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * 
	 * @see java.awt.Graphics2D#drawOval(int, int, int, int)
	 */
	public void drawOval(int x, int y, int width, int height) {
		g2.drawOval(x, y, width, height);
	}

	/**
	 * Fills the specified oval
	 * 
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * 
	 * @see java.awt.Graphics#fillOval(int, int, int, int)
	 */
	public void fillOval(int x, int y, int width, int height) {
		g2.fillOval(x, y, width, height);
	}
	
	/**
	 * Draws a closed polygon defined by arrays of x and y coordinates. Each pair of (x, y) coordinates defines a point. 
	 * 
	 * @param xPoints Array of X coordinates (int)
	 * @param yPoints Array of Y coordinates (int)
	 * @param nPoints Number of points to draw
	 * 
	 * @see java.awt.Graphics#drawPolygon(int[], int[], int)
	 */
	public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
		g2.drawPolygon(xPoints, yPoints, nPoints);
	}
	
	/**
	 * Fills a closed polygon defined by arrays of x and y coordinates.
	 * 
	 * @param xPoints Array of X coordinates (int)
	 * @param yPoints Array of Y coordinates (int)
	 * @param nPoints Number of points to draw
	 * 
	 * @see java.awt.Graphics#fillPolygon(int[], int[], int)
	 */
	public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
		g2.fillPolygon(xPoints, yPoints, nPoints);
	}

	/**
	 * Sets the drawing (pen) color of the canvas
	 * 
	 * @param r
	 *            Red value (0.0 - 1.0)
	 * @param g
	 *            Green value (0.0 - 1.0)
	 * @param b
	 *            Blue value (0.0 - 1.0)
	 * @param a
	 *            Alpha value (0.0 - 1.0)
	 */
	public void setColor(float r, float g, float b, float a) {
		Color c = new Color(r, g, b, a);
		g2.setColor(c);
	}

	/**
	 * Sets the drawing (pen) color of the canvas (alpha value is set to 1.0 -
	 * fully opaque)
	 * 
	 * @param r
	 *            Red value (0.0 - 1.0)
	 * @param g
	 *            Green value (0.0 - 1.0)
	 * @param b
	 *            Blue value (0.0 - 1.0)
	 */
	public void setColor(float r, float g, float b) {
		Color c = new Color(r, g, b);
		g2.setColor(c);
	}

	/**
	 * Sets the drawing (pen) color of the canvas
	 * 
	 * @param hColor
	 *            Hex representation of the color value (e.g. Red = 0xFF0000)
	 */
	public void setColor(String hColor) {
		Color c = Color.decode(hColor);
		g2.setColor(c);
	}

	/**
	 * Sets the drawing (pen) color of the canvas
	 * 
	 * @param c An instance of java.awt.Color
	 *         
	 * @see java.awt.Color
	 */
	public void setColor(Color c) {
		g2.setColor(c);
	}

	/**
	 * 
	 * @return Current drawing (pen) color
	 */
	public Color getColor() {
		return g2.getColor();
	}

	/**
	 * Resizes the Canvas to the specified width and height Note: Width cannot
	 * exceed MAX_WIDTH value; Height cannot exceed MAX_HEIGHT value
	 * 
	 * @param width
	 *            Target canvas width
	 * @param height
	 *            Target canvas height
	 * 
	 * @throws InvalidParameterException
	 * 
	 * @see org.jdraw.Canvas#MAX_WIDTH
	 * @see org.jdraw.Canvas#MAX_HEIGHT
	 */
	public void setSize(int width, int height) {
		if (width > MAX_WIDTH) {
			throw new IllegalArgumentException(
					"width cannot be greater than MAX_WIDTH (" + MAX_WIDTH
							+ ")");
		}
		if (height > MAX_HEIGHT) {
			throw new IllegalArgumentException(
					"height cannot be greater than MAX_HEIGHT (" + MAX_HEIGHT
							+ ")");
		}
		this.width = width;
		this.height = height;
		reset();
	}

	/**
	 * 
	 * @return The current width of the canvas
	 */
	public int getWidth() {
		return this.width;
	}

	/**
	 * 
	 * @return The current height of the canvas
	 */
	public int getHeight() {
		return this.height;
	}

}
